﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Mbs.Reflection;
using NUnit.Framework;

namespace Mbs.Test.Reflection
{
    [TestFixture]
    public class ClassLoaderTest
    {
        protected virtual IClassLoader CreateClassLoader()
        {
            var loader = new ClassLoader();
            Assert.IsTrue(loader.IsDefault);
            return loader;
        }

         [Test]
        public void DisplayMbsInterfaceCounts()
        {
            var types = typeof(ILauncher).Assembly.GetTypes();
            var interC = (from t in types
                          where t.IsInterface
                          select t).Count();
            var classC = (from t in types
                          where t.IsClass
                          select t).Count();

            Console.WriteLine("Interfaces:" + interC.ToString());
            Console.WriteLine("classes:" + classC.ToString());

            Console.WriteLine(typeof(List<>).Assembly.FullName);
            Console.WriteLine(typeof(List<int>).FullName);
            Console.WriteLine(typeof(Dictionary<int,string>).FullName);
            Console.WriteLine(typeof(IGenericType<,,,>).FullName);
            Console.WriteLine(Assembly.GetExecutingAssembly().FullName);
        }

      

        interface IGenericType<T1, T2, T3, T4>
        {

        }

        [Test]
        public void GenericNameTest()
        {
            var expectedListType = "System.Collections.Generic.IList`1";
            Assert.AreEqual(expectedListType, typeof(IList<>).FullName);

            expectedListType = "System.Collections.Generic.Dictionary`2";
            Assert.AreEqual(expectedListType, typeof(Dictionary<,>).FullName);

            expectedListType = "System.Collections.Generic.IList`1[[System.Int32]]";

            var classLoader = CreateClassLoader();
            var type = classLoader.LoadType("System.Collections.Generic.List`1[[System.Int32,mscorlib]],mscorlib");
            Assert.IsNotNull(type);


            type = classLoader.LoadType("Mbs.Test.Reflection.ClassLoaderTest+IGenericType`4,Mbs.Test");
            Assert.IsNotNull(type);


            type = classLoader.LoadType("Mbs.Test.Reflection.ClassLoaderTest+IGenericType`4[[System.Int32,mscorlib],[System.String,mscorlib],[System.Object,mscorlib],[System.Boolean,mscorlib]],Mbs.Test");
            Assert.IsNotNull(type);


            type = classLoader.LoadType("Mbs.Test.Reflection.ClassLoaderTest+IGenericType`4,Mbs.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
            Assert.IsNotNull(type);

            type = classLoader.LoadType("Mbs.Test.Reflection.ClassLoaderTest+IGenericType`4[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],Mbs.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
            Assert.IsNotNull(type);

        }

        [Test]
        public void NewInstanceTest()
        {
            var classLoader = CreateClassLoader();
           
            var o = classLoader.NewInstance<TestClass>();
            Assert.IsNotNull(o);
            Assert.IsTrue(o.HasVisited);

            var o2 = classLoader.NewInstance<TestClass>(100);
            Assert.IsNotNull(o2);
            Assert.IsTrue(o2.Arg1 == 100);

            var o3 = classLoader.NewInstance("Mbs.Test.Reflection.ClassLoaderTest+TestClass,Mbs.Test", 50) as TestClass;
            Assert.IsNotNull(o3);
            Assert.IsTrue(o3.Arg1 == 50);

            var o4 = classLoader.NewInstance<TestClass>("Mbs.Test.Reflection.ClassLoaderTest+TestClass,Mbs.Test", 50) ;
            Assert.IsNotNull(o4);
            Assert.IsTrue(o4.Arg1 == 50);

            var o5 = classLoader.NewInstance<IList<int>>(typeof(List<int>));
            Assert.IsNotNull(o5);
        }

        [Test]
        public void InvokeTest()
        {
            Func<ConstructorInfo> newHandler = () => typeof(TestClass).GetConstructor(Type.EmptyTypes);

            var classLoader = CreateClassLoader();
            var o = (classLoader.Invoke(newHandler)as ConstructorInfo).FastInvoke(null) as TestClass;
            Assert.IsNotNull(o);
            Assert.IsTrue(o.HasVisited);

        }

        [Test]
        public void LoadAssemblyTest()
        {
            var classLoader = CreateClassLoader();
            var asm1 = classLoader.LoadAssembly("AspectSharp.dll");
            Assert.IsNotNull(asm1);

            var asm2 = classLoader.LoadAssembly("AspectSharp.dll");
            Assert.IsNotNull(asm2);

            Assert.AreSame(asm1, asm2);
            classLoader.Dispose();
        }

        [Test]
        public void LoadAssembliesTest()
        {
            var classLoader = CreateClassLoader();
            var beforeAssemblyCount = classLoader.GetAssemblies().Length;
           classLoader.LoadAssemblies(AppDomain.CurrentDomain.BaseDirectory);
           var afterAssemblyCount = classLoader.GetAssemblies().Length;

           Assert.IsTrue(afterAssemblyCount > beforeAssemblyCount);
           
           
        }

        [Test]
        public virtual void LoadAssembliesTest2()
        {
            var classLoader = CreateClassLoader();
            var beforeAssemblyCount = classLoader.GetAssemblies().Length;
            //classLoader.LoadAssemblies(AppDomain.CurrentDomain.BaseDirectory,true);
            //var afterAssemblyCount = classLoader.GetAssemblies().Length;

            //Assert.IsTrue(afterAssemblyCount > beforeAssemblyCount);
            classLoader.Dispose();
        }

      

        [Serializable]
        class TestClass
        {
            public bool HasVisited;
            public TestClass()
            {
                HasVisited = true;
            }

            public int Arg1;

            public TestClass(int a1)
            {
                Arg1 = a1;
            }
        }


    }

    //[TestFixture]
    //public class RemoteClassLoaderTest : ClassLoaderTest
    //{
    //    protected override IClassLoader CreateClassLoader()
    //    {
    //        var loader = new RemoteClassLoader(false);
    //        Assert.IsFalse(loader.IsDefault);
    //        return loader;
    //    }

    //    public override void LocatorTest()
    //    {
            
    //    }

    //    public override void LoadAssembliesTest2()
    //    {
            
    //    }
        
    //}
}
